package cn.bearspark.comment.provider.service.impl;

import cn.bearspark.comment.dto.*;
import cn.bearspark.comment.provider.dao.buffer.BldgCommentBuffer;
import cn.bearspark.comment.provider.dao.buffer.BldgCommentIdListBuffer;
import cn.bearspark.comment.provider.dao.buffer.LayerCommentBuffer;
import cn.bearspark.comment.provider.dao.buffer.LayerCommentIdPageListBuffer;
import cn.bearspark.comment.provider.dao.co.BldgCommentCO;
import cn.bearspark.comment.provider.dao.co.LayerCommentCO;
import cn.bearspark.comment.provider.dao.mapper.BldgCommentMapper;
import cn.bearspark.comment.provider.dao.mapper.CommentContentMapper;
import cn.bearspark.comment.provider.dao.mapper.LayerCommentMapper;
import cn.bearspark.comment.provider.service.CommentService;
import cn.bearspark.common.dto.Page;
import cn.bearspark.common.util.ConvertInfoUtil;
import cn.bearspark.idgenerator.rpc.CommentIdGeneratorRpc;
import cn.bearspark.common.enumeration.LikedEnum;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author f
 */
@Service
public class CommentServiceImpl implements CommentService {

    @DubboReference
    private CommentIdGeneratorRpc commentIdGeneratorRpc;

    private final BldgCommentMapper bldgCommentMapper;
    private final LayerCommentMapper layerCommentMapper;
    private final CommentContentMapper commentContentMapper;

    private final BldgCommentBuffer bldgCommentBuffer;
    private final BldgCommentIdListBuffer bldgCommentIdListBuffer;
    private final LayerCommentBuffer layerCommentBuffer;
    private final LayerCommentIdPageListBuffer layerCommentIdListBuffer;

    public CommentServiceImpl(BldgCommentMapper bldgCommentMapper,
                              LayerCommentMapper layerCommentMapper,
                              CommentContentMapper commentContentMapper,
                              BldgCommentBuffer bldgCommentBuffer,
                              BldgCommentIdListBuffer bldgCommentIdListBuffer,
                              LayerCommentBuffer layerCommentBuffer,
                              LayerCommentIdPageListBuffer layerCommentIdListBuffer) {
        this.bldgCommentMapper = bldgCommentMapper;
        this.layerCommentMapper = layerCommentMapper;
        this.commentContentMapper = commentContentMapper;
        this.bldgCommentBuffer = bldgCommentBuffer;
        this.bldgCommentIdListBuffer = bldgCommentIdListBuffer;
        this.layerCommentBuffer = layerCommentBuffer;
        this.layerCommentIdListBuffer = layerCommentIdListBuffer;
    }

    @Override
    public void like(long commentId, int liked) {
        if (isBldgComment(commentId)) {
            if (liked == LikedEnum.LIKED.getCode()) {
                bldgCommentMapper.incrLikeNum(commentId);
            } else {
                bldgCommentMapper.decrLikeNum(commentId);
            }

            // 清理楼评论的热数据
            bldgCommentBuffer.cleanHot(commentId);
        } else {
            if (liked == LikedEnum.LIKED.getCode()) {
                layerCommentMapper.incrLikeNum(commentId);
            } else {
                layerCommentMapper.decrLikeNum(commentId);
            }

            // 清理层评论的热数据
            layerCommentBuffer.cleanHot(commentId);
        }
    }

    @Override
    public Page<BldgCommentDTO> pageQueryHappening(int pageNum, int pageSize, long happeningId, int order) {
        // 查询评论 id 的分页信息
        Page<Long> commentIdPage = bldgCommentIdListBuffer.pageHappeningBldgId(pageNum, pageSize, happeningId, order);

        // 查询评论的信息
        List<Long> commentIdList = commentIdPage.getRecords();
        Map<Long, BldgCommentCO> bldgCommentCOMap = bldgCommentBuffer.map(commentIdList);

        // 组装对象并返回
        Page<BldgCommentDTO> bldgCommentDTOPage = new Page<>();
        bldgCommentDTOPage.setTotal(commentIdPage.getTotal());
        bldgCommentDTOPage.setRecords(commentIdList.stream().map(bldgCommentId ->
                ConvertInfoUtil.convert(bldgCommentCOMap.get(bldgCommentId), BldgCommentDTO.class)
        ).filter(Objects::nonNull).toList());
        return bldgCommentDTOPage;
    }

    @Override
    public List<LayerCommentDTO> pageQueryLayer(int pageNum, int pageSize, long commentId) {
        // 查询层评论 id 集合
        List<Long> commentIdList = layerCommentIdListBuffer.page(commentId, pageNum, pageSize);

        // 查询层评论的信息
        Map<Long, LayerCommentCO> layerCommentCOMap = layerCommentBuffer.map(commentIdList);

        return commentIdList.stream().map(layerCommentId ->
                ConvertInfoUtil.convert(layerCommentCOMap.get(layerCommentId), LayerCommentDTO.class)
        ).filter(Objects::nonNull).toList();
    }

    @Override
    public long commentHappening(HappeningReqDTO happeningReqDTO) {
        long happeningId = happeningReqDTO.getHappeningId();
        long commentId = commentIdGeneratorRpc.genBldgId();
        bldgCommentMapper.insert(commentId, happeningReqDTO.getUserId(), happeningId);
        commentContentMapper.insert(commentId, happeningReqDTO.getContent());

        // 清理动态的楼评论 id 集合缓存
        bldgCommentIdListBuffer.cleanHappening(happeningId);

        return commentId;
    }

    @Override
    public ReplyRespDTO reply(ReplyReqDTO replyReqDTO) {
        long repliedCommentId = replyReqDTO.getRepliedCommentId();

        // 获取本评论所在的楼评论 id
        boolean isBldgComment = isBldgComment(repliedCommentId);
        long bldgCommentId = !isBldgComment ?
                layerCommentMapper.getBldgCommentId(repliedCommentId) :
                repliedCommentId;

        // 增加楼评论的回复数
        bldgCommentMapper.incrReplyNum(bldgCommentId);

        // 清理楼评论的热数据
        bldgCommentBuffer.cleanHot(bldgCommentId);

        // 添加层评论的记录
        long commentId = commentIdGeneratorRpc.genLayerId();
        layerCommentMapper.insert(commentId, replyReqDTO.getUserId(),
                isBldgComment ? null : replyReqDTO.getRepliedUserId(), bldgCommentId);
        commentContentMapper.insert(commentId, replyReqDTO.getContent());

        // 清理楼评论下的层评论 id 集合缓存
        layerCommentIdListBuffer.clean(bldgCommentId);

        // 查询楼评论的动态 id 并返回
        ReplyRespDTO replyRespDTO = new ReplyRespDTO();
        replyRespDTO.setHappeningId(bldgCommentMapper.getBldgHappeningId(bldgCommentId));
        replyRespDTO.setReplyCommentId(commentId);
        return replyRespDTO;
    }

    @Override
    public DeleteRespDTO delete(long userId, long commentId) {
        long deleted;
        Long bldgHappeningId;

        Long bldgCommentId;

        if (isBldgComment(commentId)) {
            bldgCommentId = commentId;

            // 如果查询不到楼评论的动态 id，则直接返回
            bldgHappeningId = bldgCommentMapper.getBldgHappeningIdWithUserId(commentId, userId);
            if (bldgHappeningId == null) {
                return null;
            }

            // 删除所有回复的层评论
            deleted = layerCommentMapper.deleteByBldgId(commentId) + 1;

            // 删除楼评论
            bldgCommentMapper.delete(commentId);

            // 清理楼评论的数据
            bldgCommentBuffer.clean(commentId);
        } else {
            // 如果查询不到层评论的数据，则直接返回
            bldgCommentId = layerCommentMapper.getBldgCommentIdWithUserId(commentId, userId);
            if (bldgCommentId == null) {
                return null;
            }

            // 删除层评论
            layerCommentMapper.delete(commentId);
            deleted = 1;

            // 减少楼评论的回复数
            bldgCommentMapper.decrReplyNum(bldgCommentId);

            // 清理楼评论的热数据
            bldgCommentBuffer.cleanHot(bldgCommentId);

            // 查询楼评论的动态 id
            bldgHappeningId = bldgCommentMapper.getBldgHappeningId(bldgCommentId);
        }

        // 删除层评论 id 的缓存
        layerCommentIdListBuffer.clean(bldgCommentId);

        // 构造响应对象并返回
        DeleteRespDTO deleteRespDTO = new DeleteRespDTO();
        deleteRespDTO.setHappeningId(bldgHappeningId);
        deleteRespDTO.setDeleted(deleted);
        return deleteRespDTO;
    }

    // 判断评论是不是楼评论，也就是判断评论 id 是否是奇数
    private boolean isBldgComment(long commentId) {
        return (commentId & 1) == 1;
    }
}
